package org.jeecgframework.core.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * 
 * @author caizw
 * 
 * @createDate 2018/2/8
 * 
 * @description 反射工具类
 * 
 */

public class ReflectUtils {

	/**
	 * 
	 * 获取实体类主键
	 *
	 * 
	 * 
	 * @param clazz
	 * 
	 * @return
	 * @throws Exception
	 * 
	 */

	public static Field getIdField(Class<?> clazz) throws Exception {

		Field[] fields = clazz.getDeclaredFields();

		Field item = null;

		for (Field field : fields) {
			Method m = getGetMethod(clazz, field.getName());

			Id id = m.getAnnotation(Id.class);

			if (id != null) {

				field.setAccessible(true);

				item = field;

				break;

			}

		}

		if (item == null) {

			Class<?> superclass = clazz.getSuperclass();

			if (superclass != null) {

				item = getIdField(superclass);

			}

		}

		return item;

	}

	/**
	 * 
	 * 根据主键名称获取实体类主键属性值
	 *
	 * 
	 * 
	 * @param clazz
	 * 
	 * @param pkName
	 * 
	 * @return
	 * 
	 */

	public static Object getPkValueByName(Object clazz, String pkName) {

		try {

			String firstLetter = pkName.substring(0, 1).toUpperCase();

			String getter = "get" + firstLetter + pkName.substring(1);

			Method method = clazz.getClass().getMethod(getter, new Class[] {});

			Object value = method.invoke(clazz, new Object[] {});

			return value;

		} catch (Exception e) {

			return null;

		}

	}

	/**
	 * 
	 * 通过反射将 class1不为空的值赋值给class2
	 *
	 * 
	 * 
	 * @param class1
	 * 
	 * @param class2
	 * 
	 * @throws Exception
	 * 
	 */

	public static void reflectClass1ToClass2(Object class1, Object class2) throws Exception {

		Field[] field = class1.getClass().getDeclaredFields();

		for (int i = 0; i < field.length; i++) {

			String name = field[i].getName();

			if ("serialVersionUID".equals(name)) {

				continue;

			}

			name = name.substring(0, 1).toUpperCase() + name.substring(1);

			Method m1 = class1.getClass().getMethod("get" + name);

			Object value = m1.invoke(class1);

			if (value != null) {

				Field f = field[i];

				f.setAccessible(true);

				f.set(class2, value);

			}

		}

	}

	/**
	 * 
	 * 获取实体类 @Column 的其中一个属性名称
	 *
	 * 
	 * 
	 * @param clazz
	 * 
	 * @return
	 * 
	 */

	public static Map<String, String> getColumnName(Class<?> clazz) {

		Map<String, String> map = new ConcurrentHashMap<>();

		Field[] fields = clazz.getDeclaredFields();

		for (Field field : fields) {
			Method m = null;
			try {
				m = getGetMethod(clazz, field.getName());
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			if (m != null) {
				if (m.isAnnotationPresent(Column.class)) {

					/**
					 * 
					 * 获取字段名
					 * 
					 */

					Column declaredAnnotation = m.getAnnotation(Column.class);

					String column = declaredAnnotation.name();

					map.put(field.getName(), column);

					// map.put("column", column);

					// break;

				}
			}

		}

		return map;

	}

	/**
	 * 
	 * 通过获取类上的@Table注解获取表名称
	 *
	 * 
	 * 
	 * @param clazz
	 * 
	 * @return
	 * 
	 */

	public static Map<String, String> getTableName(Class<?> clazz) {

		Map<String, String> map = new ConcurrentHashMap<>();

		Table annotation = clazz.getAnnotation(Table.class);

		String name = annotation.name();

		String className = clazz.getSimpleName();

		map.put("tableName", name);

		map.put("className", className);

		return map;

	}

	/**
	 * 根据属性，获取get方法
	 * 
	 * @param ob
	 *            对象
	 * @param name
	 *            属性名
	 * @return
	 * @throws Exception
	 */
	public static Method getGetMethod(Class<?> clazz, String name) throws Exception {
		Method[] m = clazz.getMethods();
		for (int i = 0; i < m.length; i++) {
			if (("get" + name).toLowerCase().equals(m[i].getName().toLowerCase())) {
				return m[i];
			}
		}
		return null;
	}

	/**
	 * 根据属性，拿到set方法，并把值set到对象中
	 * 
	 * @param obj
	 *            对象
	 * @param clazz
	 *            对象的class
	 * @param fileName
	 *            需要设置值得属性
	 * @param typeClass
	 * @param value
	 */
	public static void setValue(Object obj, Class<?> clazz, String filedName, Class<?> typeClass, Object value) {
		filedName = removeLine(filedName);
		String methodName = "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
		try {
			Method method = clazz.getDeclaredMethod(methodName, new Class[] { typeClass });
			method.invoke(obj, new Object[] { getClassTypeValue(typeClass, value) });
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * 通过class类型获取获取对应类型的值
	 * 
	 * @param typeClass
	 *            class类型
	 * @param value
	 *            值
	 * @return Object
	 */
	private static Object getClassTypeValue(Class<?> typeClass, Object value) {
		if (typeClass == int.class || value instanceof Integer) {
			if (null == value) {
				return 0;
			}
			return value;
		} else if (typeClass == int.class || value instanceof BigInteger) {
			if (null == value) {
				return 0;
			}
			return Integer.valueOf(value + "");
		} else if (typeClass == int.class || value instanceof Long) {
			if (null == value) {
				return 0;
			}
			return Integer.valueOf(value + "");
		} else if (typeClass == short.class) {
			if (null == value) {
				return 0;
			}
			return value;
		} else if (typeClass == byte.class) {
			if (null == value) {
				return 0;
			}
			return value;
		} else if (typeClass == double.class) {
			if (null == value) {
				return 0;
			}
			return value;
		} else if (typeClass == long.class) {
			if (null == value) {
				return 0;
			}
			return value;
		} else if (typeClass == String.class) {
			if (null == value) {
				return "";
			}
			return value;
		} else if (typeClass == boolean.class) {
			if (null == value) {
				return true;
			}
			return value;
		} else if (typeClass == BigDecimal.class) {
			if (null == value) {
				return new BigDecimal(0);
			}
			return new BigDecimal(value + "");
		} else {
			return typeClass.cast(value);
		}
	}

	// /**
	// * 通过class类型对应类型的值转换成字符串
	// *
	// * @param typeClass
	// * class类型
	// * @param value
	// * 值
	// * @return Object
	// */
	// public static <T> T getStringforValue(Class<?> typeClass, T entity) {
	//
	// Field[] fields = typeClass.getFields();
	// for (Field f : fields) {
	// if (f.getType() == java.util.Date.class || f.getType() ==
	// java.sql.Date.class) {
	// setValue(entity, entity.getClass(), f.getName(), typeClass, value);
	// entity.put(f.getName(), DateUtils.dateformat(map.get(f.getName()),
	// "yyyy-mm-dd HH:MI:SS"));
	// }
	// }
	//
	// return entity;
	// }

	/**
	 * 处理字符串 如： abc_dex ---> abcDex
	 * 
	 * @param str
	 * @return
	 */
	public static String removeLine(String str) {
		if (null != str && str.contains("_")) {
			int i = str.indexOf("_");
			char ch = str.charAt(i + 1);
			char newCh = (ch + "").substring(0, 1).toUpperCase().toCharArray()[0];
			String newStr = str.replace(str.charAt(i + 1), newCh);
			String newStr2 = newStr.replace("_", "");
			return newStr2;
		}
		return str;
	}

	/**
	 * 获取类属性的类型
	 */

	public static Map<String, Class<?>> getClassPropertyType(Class<?> clazz) {

		Map<String, Class<?>> map = new ConcurrentHashMap<>();

		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {

			map.put(field.getName(), field.getType());

		}

		return map;

	}

	/**
	 * 根据属性名称获取类属性的类型
	 * 
	 * @throws SecurityException
	 * @throws NoSuchFieldException
	 */

	public static Class<?> getClassPropertyTypebyname(Class<?> clazz, String name)
			throws NoSuchFieldException, SecurityException {

		Field[] fields = clazz.getDeclaredFields();
		return clazz.getField(name).getType();

	}

}
